<template>
  <t-dialog
    v-model:visible="visible"
    attach="body"
    :close-on-esc-keydown="mode === 'read'"
    :close-on-overlay-click="mode === 'read'"
    destroy-on-close
    :header="computedHeader"
    @closed="handleClosed"
  >
    <t-skeleton :loading="loadingSkeleton" animation="gradient">
      <t-form ref="formRef" :data="formData" reset-type="initial" @submit="handleSave" :label-width="props.labelWidth">
        <slot :mode="mode" :form-data="formData" :readonly="mode === 'read'"></slot>
      </t-form>
    </t-skeleton>
    <template #footer>
      <t-button theme="default" @click="handleCancel">取消</t-button>
      <t-button v-show="mode === 'update'" theme="warning" @click="handleReset">重置</t-button>
      <t-button v-show="mode === 'create' || mode === 'update'" :loading="loadingSubmit" :disabled="loadingSubmit" @click="formRef?.submit">
        保存
      </t-button>
    </template>
  </t-dialog>
</template>

<script setup lang="ts">
import { FormInstanceFunctions, MessagePlugin, SubmitContext } from 'tdesign-vue-next';
import { computed, nextTick, PropType, ref, useTemplateRef, watch } from 'vue';

import { ApiMap } from './type';

const props = defineProps({
  apiMap: {
    type: Object as PropType<ApiMap>,
    required: true,
  },
  header: {
    type: String,
    default: '*',
  },
  onBeforeSetData: {
    type: Function as PropType<(data: any) => any>,
  },
  onBeforeSaveData: {
    type: Function as PropType<(data: any) => any>,
  },
  labelWidth: {
    type: Number,
    default: 100
  },
  updateSucessTip: {
    type: String,
    default: '编辑成功'
  }

});
const emits = defineEmits(['requestSuccess','refresh']);
const mode = ref<'create' | 'read' | 'update'>('create');
const visible = ref(false);
const loadingSkeleton = ref(false);
const loadingSubmit = ref(false);
const computedHeader = computed(() => {
  let result = props.header;
  const modeMap = {
    create: '新建',
    read: '查看',
    update: '编辑',
  };
  result = result.replaceAll('*', modeMap[mode.value]);
  return result;
});
const formRef = useTemplateRef<FormInstanceFunctions>('formRef');
const formData = ref<Record<string, any>>({});
const open = async (m: 'create' | 'read' | 'update', params: Record<string, any>) => {
  mode.value = m;
  visible.value = true;
  if (m === 'read' || m === 'update') {
    loadingSkeleton.value = true;
    try {
      let data = {};
      if ((props.apiMap as ApiMap).get) {
        data = await (props.apiMap as ApiMap).get(params);
      }
      if (props.onBeforeSetData && typeof props.onBeforeSetData === 'function') {
        data = props.onBeforeSetData(data) || data;
      }
      await nextTick(); // 等待模板渲染完成，否则Form无法监听到初始值
      formData.value = { ...params, ...data };
    } catch ({ message }) {
      MessagePlugin.error(message);
    } finally {
      loadingSkeleton.value = false;
    }
  } else {
    formData.value = { ...params };
  }
};
const handleReset = () => {
  formRef.value.reset();
};
const handleSave = ({ validateResult }: SubmitContext) => {
  if (validateResult !== true) return;
  let params = {
    ...formData.value,
  };
  if (props.onBeforeSaveData && typeof props.onBeforeSaveData === 'function') {
    const result = props.onBeforeSaveData(params);
    if (typeof result === 'boolean' && result === false) {
      return;
    }
    params = result || params;
  }
  loadingSubmit.value = true;
  (props.apiMap as ApiMap)
    [mode.value as 'create' | 'update'](params)
    .then((data) => {
      if(props.updateSucessTip!='false') {
        MessagePlugin.success({ create: '新建成功', update: props.updateSucessTip }[mode.value as 'create' | 'update']);
      }
      emits('requestSuccess', { mode: mode.value, data, params });
      visible.value = false;
    })
    .catch(({ message }) => {
      MessagePlugin.error(message);
    })
    .finally(() => {
      loadingSubmit.value = false;
    });
};
const handleClosed = () => {
  formData.value = {};
};
const handleCancel = () => {
  visible.value = false;
};
watch(visible, (newVal) => {
  if(newVal===false) {
    emits('refresh');
  }
});
defineExpose({
  open,
  formData,
  visible
});
</script>

<style lang="less" scoped></style>
